using System;

namespace PoolKit
{
    /// <summary>
    /// Pool of resources
    /// </summary>
    /// <typeparam name="TResource"></typeparam>
	public abstract class Pool<TResource> : IDisposable
        where TResource: class
	{
		/// <summary>
		/// Asks the pool to lend you a resource
		/// </summary>
		/// <returns>
		/// A resource borrowed from pool
		/// </returns>
		/// <exception cref="CannotLendResourceException"></exception>
		/// <exception cref="ObjectDisposedException"></exception>
		public abstract TResource Lend();

        /// <summary>
        /// Asks the pool to give up a resource to you - after this the pool no longer tracks the
        /// resource and you cannot return it to the pool
        /// </summary>
        /// <returns>
        /// A resource from pool
        /// </returns>
        /// <exception cref="CannotGiveUpResourceException"></exception>
        /// <exception cref="ObjectDisposedException"></exception>
        public abstract TResource GiveUp();
		
        /// <summary>
        /// Asks the pool to lend you a resource
        /// </summary>
        /// <param name="resource">A resource borrowed from pool</param>
        /// <returns>True, if the resource has been lent, False - otherwise</returns>
        /// <exception cref="ObjectDisposedException"></exception>
		internal abstract bool TryLend(out TResource resource);
		
        /// <summary>
        /// Returns a previously borrowed resource to the pool
        /// </summary>
        /// <param name="resource">A previously borrowed resource to be returned</param>
        /// <exception cref="CannotAcceptResourceException"></exception>
        /// <exception cref="ArgumentNullException"></exception>
        /// <exception cref="ObjectDisposedException"></exception>
		public abstract void AcceptBack(TResource resource);
		
        /// <summary>
        /// Returns a previously borrowed, broken resource to the pool
        /// </summary>
        /// <param name="resource">Broken resource to be returned.</param>
        /// <exception cref="ObjectDisposedException"></exception>
        /// <exception cref="CannotAcceptResourceException"></exception>
        /// <exception cref="ArgumentNullException"></exception>
		public abstract void AcceptBackBroken(TResource resource);
		
        /// <summary>
        /// Disposes of the pool
        /// </summary>
		public abstract void Dispose();        
	}
}